﻿using System;
using System.Text.RegularExpressions;
using System.Windows.Controls;
using System.Windows.Input;

namespace FFmpegVideoClip
{
    //TextBox时间输入模式控制
    public sealed class TextBoxTextTimeInputChangedLimit: TextBoxTextChangedLimit
    {
        public const string DefaultHistorical = "0000:00:00.000";
        public TextBoxTextTimeInputChangedLimit() : base()
        {
            TextChanged += TimeLimitTextChangedCheck;
        }

        public override void RegisterControl(TextBox control)
        {
            if (controls.ContainsKey(control))
                return;
            control.PreviewTextInput += TimeLimitPreviewTextInput;
            control.PreviewMouseDown += Control_PreviewMouseDown;
            control.TextChanged += Control_TextChanged;
            controls.Add(control, DefaultHistorical);
        }

        public override void UnRegisterControl(TextBox control)
        {
            control.PreviewTextInput -= TimeLimitPreviewTextInput;
            base.UnRegisterControl(control);
        }
        
        public void TimeLimitPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            if (!(int.TryParse(e.Text, out int xx) || e.Text.Equals(":")))
            {
                e.Handled = true;
                return;
            }

            TextBox textBox = (TextBox)sender;
            if (textBox.CaretIndex >= 14)
            {
                textBox.CaretIndex = 14;
                e.Handled = true;
                return;
            }

            void TextBoxSetTest(string Value)
            {
                EnableTextChangedEvent = false;
                textBox.SelectionStart = textBox.CaretIndex;
                textBox.SelectionLength = 1;
                textBox.SelectedText = Value;
                textBox.SelectionLength = 0;
                ++textBox.CaretIndex;
                EnableTextChangedEvent = true;
            }

            if (textBox.CaretIndex == 4 || textBox.CaretIndex == 7)
                TextBoxSetTest(":");

            else if (textBox.CaretIndex == 10)
                TextBoxSetTest(".");

            TextBoxSetTest(e.Text);
            e.Handled = true;
        }

        public void TimeLimitTextChangedCheck(TextBox textBox, string Value)
        {
            int CaretIndex;
            void InsertText(string value, bool EnableCheckEquals = false)
            {
                CaretIndex = textBox.CaretIndex;
                textBox.SelectionStart = CaretIndex;
                textBox.SelectionLength = 1;
                if (EnableCheckEquals && textBox.SelectedText.Equals(value, StringComparison.Ordinal))
                {
                    textBox.SelectionLength = 0;
                    return;
                }
                textBox.SelectionLength = 0;
                EnableTextChangedEvent = false;
                textBox.Text = textBox.Text.Insert(textBox.CaretIndex, value);
                EnableTextChangedEvent = true;
                textBox.CaretIndex = CaretIndex;
            }

            if (textBox.CaretIndex == 4 || textBox.CaretIndex == 7)
                InsertText(":", true);

            else if (textBox.CaretIndex == 10)
                InsertText(".", true);

            if (!Regex.IsMatch(textBox.Text, @"^\d{4}:\d{2}:\d{2}.\d{3}$"))
            {
                if (TimeTextFormat(textBox.Text,out string Result))
                {
                    EnableTextChangedEvent=false;
                    textBox.Text = Result;
                    EnableTextChangedEvent = true;
                }
                else
                {
                    EnableTextChangedEvent=false;
                    CaretIndex = textBox.CaretIndex;
                    textBox.Text = Value;
                    textBox.CaretIndex = CaretIndex - 1;
                    EnableTextChangedEvent = true;
                }
            }
        }

        private static bool TimeTextFormat(string value, out string Result)
        {
            Result = string.Empty;
            if (string.IsNullOrWhiteSpace(value))
                return false;
            
            string[] SA = value.Split([':', '.'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            Span<uint> ints = stackalloc uint[SA.Length];

            for (int i = 0; i < ints.Length; i++)
            {
                if (!uint.TryParse(SA[i], out uint Number))
                    return false;
                ints[i] = Number;
            }

            Result = ints.Length switch
            {
                1 => $"0000:00:00.{ints[0].ToString("000")}",
                2 => $"0000:00:{ints[0].ToString("00")}.{ints[1].ToString("000")}",
                3 => $"0000:{ints[0].ToString("00")}:{ints[1].ToString("00")}.{ints[2].ToString("000")}",
                4 => $"{ints[0].ToString("0000")}:{ints[0].ToString("00")}:{ints[0].ToString("00")}.{ints[0].ToString("000")}",
                _ => $"0000:00:00.000"
            };
            if (Result.Length != 14)
                return false;
            return true;
        }
    }

}
